import re
import os
import sublime
import sublime_plugin


# ST3限制TextCommand的run()方法结束了就不能再用它的edit参数编辑view内容了；
# 偏偏ST3中的各种回调函数都是非阻塞的，经常会出现要编辑view内容时run()已经结束了；
# 所以只好专门写个TextCommand命令用来插入内容；
class WanNengInsertCommand(sublime_plugin.TextCommand):
  def run(self, edit, inst):
    '''inst: [(pt, cotnt)]格式的list
          pt: point, 文本偏移地址
          cotnt: str, 要插入的内容
    '''
    # 遍历inst并插入所有内容
    for pt,cotnt in inst:
      self.view.insert(edit, pt, cotnt)


# 用于获取syntax文件保存目录的函数
def get_syntax_dir():
  pkgDir=sublime.packages_path() # 获取Packages目录
  staxDir=os.path.join(pkgDir, "KuaiJiSyntaxes") # 组合出Packages/KuaiJisyntaxes目录，用于存放自定义的syntax文件
  if not os.path.isdir(staxDir):
    # 如果Packages/KuaiJisyntaxes目录不存在
    # 则新建一个
    os.mkdir(staxDir)

  return staxDir


def get_template_path():
  pkgDir=sublime.packages_path()
  pkgDir=re.sub(r'\\', '/', pkgDir)
  templateName=sublime.find_resources("syntax_template.syntax-template")[0]
  templateName=re.sub(r'\\', '/', templateName)
  templateName=re.sub('Packages', '', templateName)
  return pkgDir+templateName


# 专用于打开文件的函数；
# 因为新打开的文件要准备好buffer才能编辑，而准备buffer的过程是非阻塞式的；
# 所以打开文件后立即编辑返回的view中的内容是编辑不了的；
# 所以要在打开文件后循环设置timeout直到buffer准备完毕再调用相关命令继续编辑view内容；
# 总之Python的多任务机制很垃圾，我试过很多方法，只有这个方法最实用；
def open_file(win,path,cmd):
  # sublime.set_timeout()的回调函数wait()
  def wait():
    def open_end():
      # 否则调用参数cmd命令，并传递{"opened": True}关键字参数给cmd命令；
      # 以便告诉cmd命令，文件已经打开过了
      vew.run_command(cmd, {"opened": True})


    # 如果vew的buffer还在准备中
    if vew.is_loading():
      # 继续循环设置timeout
      sublime.set_timeout(wait, 10)
    else:
      # 如果vew的buffer准备完毕，再等100毫秒(别问我为什么，我也不知道，不等就容易出错)
      sublime.set_timeout(open_end, 100)


  # 打开参数path路径指定的文件
  vew=win.open_file(path)
  # 设置timeout等待新打开的文件的buffer准备完毕
  sublime.set_timeout(wait, 10)


class KuaijiNewSyntaxCommand(sublime_plugin.TextCommand):
  def run(self, edit, opened=False):
    win=self.view.window()


    # 扩展名输入面板的回调函数get_ext_name()
    def get_ext_name(iptExNam):
      scpPt=staxVew.find(r'^scope: string source$', 0).end()
      exPt=staxVew.find(r'^file_extensions:$', 0).end()
      staxVew.set_read_only(False)
      staxVew.run_command("wan_neng_insert", {"inst": [(scpPt, '.'+iptExNam), (exPt, '\n  - '+iptExNam)]})
      staxVew.set_read_only(True)


    def on_cancel():
      staxVew.close()


    # 文件名输入面板的回调函数
    def get_file_name(iptFleNam):
      staxPath=os.path.join(staxDir, iptFleNam) # 将用户输入的文件名和Packages/KuaiJisyntaxes目录组合成完整的长文件名
      if os.path.isfile(staxPath):
        # 如果文件已存在，则弹窗提示并结束
        sublime.message_dialog("文件名已存在！")
        staxVew.close()
      else:
        # 如果文件不存在，则打开一个指向它的view：staxVew
        # 编辑完成后保存，就会新建一个对应的文件
        staxVew.retarget(staxPath)
        win.show_input_panel("请输入对象扩展名：", "", get_ext_name, None, on_cancel)


    # run()方法的正文开始
    win=self.view.window()
      # 如果还未打开
    if not opened:
      templatePath=get_template_path()
      print(templatePath)
      open_file(win, templatePath, "kuaiji_new_syntax")
    else:
      staxVew=self.view
      staxVew.set_read_only(True)
      staxDir=get_syntax_dir() # 获取存放syntax文件的目录
      if not os.path.isdir(staxDir):
        # 如果syntax目录不存在
        # 则新建一个
        os.mkdir(staxDir)

      # 弹出文件名输入面板，请求用户输入文件名
      win.show_input_panel("请输入文件名：", ".sublime-syntax", get_file_name, None, on_cancel)







class KuaijiEditSyntaxCommand(sublime_plugin.TextCommand):
  def run(self, edit, opened=False):
    win=self.view.window()
    # 让用户选择syntax文件的快捷面板的回调函数
    def on_slct(idx):
      staxPath=os.path.join(staxDir, stax_lst[idx])
      open_file(win, staxPath, "kuaiji_edit_syntax")


    def get_term(iptTerm):
      if not termEmpty and iptTerm:
        iptTerm+="|"

      if iptTerm:
        staxVew.set_read_only(False)
        staxVew.run_command("wan_neng_insert", {"inst": [(termReg.b, iptTerm)]})
        staxVew.set_read_only(True)


    def on_cancel():
      staxVew.close()
      return



    # 如果还未打开syntax文件
    if not opened:
      staxDir=get_syntax_dir()
      stax_lst=os.listdir(staxDir)
      win.show_quick_panel(stax_lst, on_slct)
    else:
      # 如果已打开
      staxVew=self.view
      # 将staxVew高为只读，防止用户手动编辑
      staxVew.set_read_only(True)
      termReg=staxVew.find("^  term: '", 0)
      staxVew.show_at_center(termReg)
      termLine=staxVew.substr(staxVew.line(termReg))
      if re.match("  term: '.+'", termLine):
        termEmpty=False
      else:
        termEmpty=True

      win.show_input_panel("请输入名词，多个名词用'|'分隔：", "", get_term, None, on_cancel)


